import useLocale from '@/utils/useLocale';
import React, { useMemo, useRef, useState } from 'react';
import moment from 'moment/moment';
import instance from '@/utils/request';
import {
  Card,
  DatePicker, Empty, Form,
  Grid, Select, Skeleton,
  Slider, Space
} from '@arco-design/web-react';
import { Chart, LineAdvance } from 'bizcharts';
import { dayjs } from '@arco-design/web-react/es/_util/dayjs';
import { OptionInfo } from '@arco-design/web-react/es/Select/interface';
import { ParameterRecord } from '@/pages/equipment/parameter';
import { convertValue } from '@/constants/functions';

const { Row, Col } = Grid;

const MonitorPanel = (props: {
  id: number,
  parameters: ParameterRecord[]
}) => {
  const t = useLocale();
  const [origins, setOrigins] = useState<{
    info: ParameterRecord,
    origin?: {
      recordTime: string,
      value: number | string | boolean | null
      time: string
    }[]
  }[]>([]);
  const [sampleRealtime, setSampleRealTime] = useState<number>(300);
  const [sample, setSample] = useState<number>(300);
  const [selectParameters, setSelectParameters] = useState<ParameterRecord[]>([]);
  const parameterOptions = useMemo(() => (props.parameters || []).map(it => {
    return {
      label: it.name,
      value: it.name,
      extra: it
    };
  }), [props.parameters]);
  const taskId = useRef(null);
  const chartOptions = useMemo(() => {
    const names = selectParameters.map(it => it.name);
    return origins.filter(it => names.includes(it.info.name))
      .map(it => {
        return {
          name: it.info.name,
          data: sampleItem(sample, it.info, it.origin)
        };
      });
  }, [sample, selectParameters, origins]);


  function shouldRefreshParameterOrigins(names: string[], records: ParameterRecord[]) {
    setSelectParameters(records);
    records.map(record => {
      if (origins.filter(it => it.info.id === record.id).length === 0) {
        // 创建记录
        const newOrigins = origins.concat({
          info: { ...record }
        });
        setOrigins(newOrigins);
        if (!!taskId.current) {
          clearTimeout(taskId.current);
        }
        taskId.current = setTimeout(() => lazyLoadData(newOrigins), 500);
      }
    });
  }

  function lazyLoadData(o) {
    const date = moment();
    const parameterIds = o.filter(it => it.origin === undefined).map(it => it.info.id);
    o = o || [];
    const chunkArray = (array: any[], chunkSize: number) => {
      if (chunkSize <= 0) {
        throw new Error('Chunk size must be a positive integer');
      }
      return array.reduce((previous, current, index) => {
        const chunkIndex = Math.floor(index / chunkSize);
        if (!previous[chunkIndex]) {
          previous[chunkIndex] = [];
        }
        previous[chunkIndex].push(current);
        return previous;
      }, []);
    };
    if (parameterIds.length > 0) {
      chunkArray(parameterIds, 3).map(it => {
        instance
          .post('/api/device/monitor', {
            deviceId: props.id,
            parameterIds: it,
            startDateTime: date.format('YYYY-MM-DD') + ' 00:00:00',
            endDateTime: date.format('YYYY-MM-DD') + ' 23:59:59'
          })
          .then((res) => {
            if (res.data.code === 200) {
              res.data.data?.paramInfos?.forEach(info => {
                o = o.map(iit => {
                  if (iit.info.id === info.info.id) {
                    iit.origin = info.records;
                  }
                  return iit;
                });
              });
              setOrigins(o);
            }
          });
      });
    }
  }

  function sampleItem(dest: number, info: { name: string, dataType: string }, data?: {
    recordTime: string,
    value: number | string | boolean | null
  }[]) {
    if (data === undefined) {
      return undefined;
    }
    const dataSeries = [];
    let lastTime = null;
    const total = data.length || 0;
    data.forEach((record, index) => {
      const now = dayjs(record.recordTime, 'YYYY-MM-DD HH:mm:ss');
      if (lastTime == null) {
        lastTime = now;
      } else if (now.diff(lastTime, 'second') >= dest || index === total - 1) {
        dataSeries.push({
          ...record,
          value: convertValue(record.value, info.dataType),
          time: record.recordTime.split(' ')[1],
          name: info.name
        });
        lastTime = now;
      }
    });
    return dataSeries;
  }

  return (
    <Card>
      <Row>
        <Form style={{ width: '100%' }} autoComplete="off" layout={'inline'}>
          <Col span={24}>
            <Row gutter={24} justify={'space-between'} align={'center'}>
              <Space style={{ flexGrow: 1, marginLeft: '24px' }}>
                <Form.Item hidden>
                  <DatePicker placeholder={t['global.query.date.desc']} style={{ width: 200 }} />
                </Form.Item>
                <Form.Item label={t['global.query.parameters']}>
                  <Select
                    mode="multiple"
                    placeholder={t['global.query.parameters.desc']}
                    style={{ width: '30rem' }}
                    defaultValue={selectParameters.map(it => it.name)}
                    allowClear
                    options={parameterOptions}
                    onChange={(value, option) => {
                      shouldRefreshParameterOrigins(value, (option as OptionInfo[]).map(it => it.extra));
                    }}>
                  </Select>
                </Form.Item>
                <Form.Item label={t['global.query.sample']}>
                  <Slider
                    style={{ width: '20rem' }}
                    min={60} max={3600} step={60}
                    marks={{
                      60: '1',
                      300: '5',
                      600: '10',
                      1200: '20',
                      1800: '30',
                      3600: '60'
                    }}
                    defaultValue={sampleRealtime}
                    onChange={(val) => setSampleRealTime(val as number)}
                    onAfterChange={(val) => setSample(val as number)}
                  />
                </Form.Item>
              </Space>
            </Row>
          </Col>
        </Form>
        <Col span={24}>
          <Row>
            {
              chartOptions.map(it => {
                return (
                  <Col span={24} key={'parameter_monitor_container_' + it.name}>
                    <Card key={'parameter_monitor_row_' + it.name}
                          bordered={true} style={{ marginTop: '1rem' }}
                          title={it.name}>
                      {
                        it.data === undefined ? (
                          <Skeleton animation />
                        ) : (
                          it.data.length === 0 ? (
                            <Empty />
                          ) : (
                            <Chart padding={[0, 50, 20, 90]} autoFit height={200} data={it.data}>
                              <LineAdvance shape="smooth" position="time*value"></LineAdvance>
                            </Chart>
                          )
                        )
                      }
                    </Card>
                  </Col>
                );
              })
            }
          </Row>
        </Col>
      </Row>
    </Card>
  );
};

export default MonitorPanel;